#ifndef FUSION_ADD_H
#define FUSION_ADD_H

template<typename InputDataType_, typename OutputDataType_>
class FusionAdd {
public:
    using InputDataType = InputDataType_;
    using OutputDataType = OutputDataType_;

    struct Arguments {};
    struct Params {};

    __host_aicore__ static Params InitParams(Arguments const& args) { return {}; }
    __host_aicore__ static size_t GetWorkSpaceSize(Arguments const& args) { return {}; }

    __aicore__ inline void Run(
        const AscendC::LocalTensor<OutputDataType>& out,
        const AscendC::LocalTensor<InputDataType>& l,
        const AscendC::LocalTensor<InputDataType>& r,
        int64_t calcElemNum
    ) {
        if constexpr (AscendC::Std::is_same_v<InputDataType, OutputDataType>) {
            AscendC::PipeBarrier<PIPE_V>();
            AscendC::Add(out, l, r, calcElemNum);
            AscendC::PipeBarrier<PIPE_V>();
        } else {
            AscendC::PipeBarrier<PIPE_V>();
            AscendC::Add(r, l, r, calcElemNum);
            AscendC::PipeBarrier<PIPE_V>();
            AscendC::Cast(out, r, AscendC::RoundMode::CAST_ROUND, calcElemNum);
            AscendC::PipeBarrier<PIPE_V>();
        }
    }

    __aicore__ inline void operator()(
        const AscendC::LocalTensor<OutputDataType>& out,
        const AscendC::LocalTensor<InputDataType>& l,
        const AscendC::LocalTensor<InputDataType>& r,
        int64_t calcElemNum
    ) {
        Run(out, l, r, calcElemNum);
    }
};

#endif